home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / HyperCard Related / XCMDs & XFCNs / DrawBitmapInRect / DrawBitmapInRect.p < prev    next >
Encoding:
Text File  |  1991-03-29  |  9.2 KB  |  380 lines  |  [TEXT/MPS ]

  1. {$R-}
  2. {$S DrawBitmapInRect }
  3.  
  4.  
  5.     DrawBitmapInRect (TargetRect, TextLabel, [DPI])
  6.  
  7.      This HyperCard XFCN creates a drawing with the bounds that are passed in
  8.     TargetRect and leaves it on the clipboard to be pasted by HyperCard.
  9.     
  10.     The drawing that results is strictly a bitmap, and hence does not contain
  11.     any draw objects (except the bitmap itself).
  12.     
  13.     TargetRect will be the picture frame of the PICT.  Its size is limited
  14.     to 0 (top and left) and 2800 (bottom and right).
  15.     
  16.     DPI is an optional parameter which defaults to 72.  It can be any
  17.     number from 72 to 400.  It is the scaling factor which determines the
  18.     spatial resolution of the bitmap that is produced.
  19.     
  20.     For instance, a DPI of 144 results in double the number of pixels in each 
  21.     direction.  A DPI of 288 results in 4 times the number of pixels in each 
  22.     direction, etc.  A 300 DPI bitmap is ideal for displaying on a LaserWriter.
  23.     
  24.     If it is successful, then empty is returned, otherwise the return value
  25.     is an error message.
  26.     
  27.     The drawing that is created is very boring: just a rectangle with an
  28.     X drawn through it, and a string drawn somewhere within it.
  29.     
  30.     Use this XFCN as a template for others that make more useful drawings.
  31.     
  32. }
  33.  
  34. UNIT DummyUnit;
  35.  
  36. INTERFACE
  37.  
  38.     USES {* ToolIntf, PackIntf, *}
  39.             Menus, Events, TextEdit, HyperXCmd, 
  40.             MemTypes, OSIntf, Scrap, QuickDraw, SANE;
  41.  
  42.     PROCEDURE EntryPoint(paramPtr: XCmdPtr);
  43.  
  44. IMPLEMENTATION
  45.  
  46.     PROCEDURE DrawBitmapInRect(paramPtr: XCmdPtr);
  47.     FORWARD;
  48.  
  49.     PROCEDURE EntryPoint(paramPtr: XCmdPtr);
  50.     BEGIN
  51.         DrawBitmapInRect(paramPtr)
  52.     END { entrypoint } ;
  53.  
  54.  
  55.     PROCEDURE DrawBitmapInRect(paramPtr: XCmdPtr);
  56.     CONST
  57.     
  58.     MinParams =        2;
  59.     MaxParams =        3;
  60.  
  61.     TYPE
  62.     
  63.     ParamArray =        PACKED ARRAY [1..MaxParams] OF Str255;
  64.  
  65.     VAR
  66.     
  67.     ParamStrings:        ParamArray;
  68.  
  69.     TargetRectParam:    Rect;
  70.     TextLabelParam:        Str255;
  71.     DPIParam:            Integer;
  72.  
  73.     ScaleFactor:        Extended;
  74.  
  75.     ThePict:            PicHandle;
  76.     TheBitMap:            BitMap;
  77.     
  78.         
  79.         PROCEDURE ExitWithString(aString: Str255);
  80.         BEGIN
  81.             WITH paramPtr^ DO BEGIN
  82.                 returnValue := PasToZero(paramPtr, aString);
  83.                 EXIT(DrawBitmapInRect);
  84.             END;
  85.         END;
  86.             
  87.         PROCEDURE ExitWithError(aString: Str255);
  88.         BEGIN
  89.             ExitWithString(concat('•••••••• Error: ', aString, '.'));
  90.         END;
  91.                                 
  92.         PROCEDURE LimitRectValue(VAR ARect: Rect);
  93.         BEGIN
  94.             IF (ARect.Left < 0) THEN ARect.Left := 0;
  95.             IF (ARect.Top < 0) THEN ARect.Top := 0;
  96.             IF (ARect.Right > 2800) THEN ARect.Right := 2800;
  97.             IF (ARect.Bottom > 2800) THEN ARect.Bottom := 2800;
  98.         END;
  99.  
  100.         PROCEDURE LimitDPIValue(VAR DPI: Integer);
  101.         BEGIN
  102.             IF (DPI < 72) THEN DPI := 72;
  103.             IF (DPI > 400) THEN DPI := 400;
  104.         END;
  105.  
  106.         { 
  107.             This is where the drawing is done.  
  108.             DrawRect is the boundary of the drawing.
  109.             
  110.             Drawing is done in whatever Quickdraw context is current -- that is,
  111.             the code in this routine should be insensitive to whether drawing
  112.             is happening inside a bitmap or inside a PICT.
  113.             
  114.             For this sample XFCN, a border is drawn around/within the given rect,
  115.             an X is drawn across the rect, and the string specified by 
  116.             TextLabelParam is drawn somewhere in the middle.
  117.           
  118.          }
  119.         FUNCTION DoTheDrawing(DrawRect: Rect): BOOLEAN;
  120.         VAR            
  121.         
  122.             PenWidth:            Integer;
  123.             PenHeight:            Integer;
  124.             
  125.             Top:                LONGINT;
  126.             Left:                LONGINT;
  127.             Bottom:                LONGINT;
  128.             Right:                LONGINT;
  129.  
  130.         BEGIN
  131.         
  132.             PenWidth := 2;
  133.             PenHeight := 2;
  134.  
  135.             Left := DrawRect.Left;
  136.             Top := DrawRect.Top;
  137.             Right := DrawRect.Right;
  138.             Bottom := DrawRect.Bottom;
  139.             
  140.             { Make some calculations -- adjusting these for the pen size }
  141.             Right := Right - PenWidth;
  142.             Bottom := Bottom - PenWidth;
  143.             
  144.             { Start drawing }
  145.             PenSize(PenWidth,PenHeight);
  146.             MoveTo(Left,Top);
  147.             LineTo(Left,Bottom);            
  148.             LineTo(Right,Bottom);            
  149.             LineTo(Right,Top);            
  150.             LineTo(Left,Top);
  151.  
  152.             MoveTo(Left,Top);
  153.             LineTo(Right,Bottom);            
  154.  
  155.             MoveTo(Right,Top);
  156.             LineTo(Left,Bottom);            
  157.  
  158.             MoveTo(Left + 30, Top + 20);    
  159.             DrawString(TextLabelParam);
  160.             
  161.             DoTheDrawing := TRUE;
  162.  
  163.         END;
  164.         
  165.         { Here we set up a 72 DPI bitmap of sufficient size so that when it is copied 
  166.           back to the destination RECT, a bitmap of DPIParam resolution will result.
  167.         }
  168.         PROCEDURE GenerateBitmap; { failure if the returned bitmap.baseAddr is NIL}
  169.         VAR
  170.  
  171.             OldGrafPtr:        GrafPtr;
  172.  
  173.             aGrafPort:        GrafPort;
  174.             aGrafPtr:        GrafPtr;
  175.         
  176.         BEGIN
  177.         
  178.             { Allocate space for the bitmap & fail if it fails }
  179.             TheBitMap.bounds.left := Num2Integer(ScaleFactor * Num2Extended(TargetRectParam.left));
  180.             TheBitMap.bounds.top := Num2Integer(ScaleFactor * Num2Extended(TargetRectParam.top));
  181.             TheBitMap.bounds.right := Num2Integer(ScaleFactor * Num2Extended(TargetRectParam.right));
  182.             TheBitMap.bounds.bottom := Num2Integer(ScaleFactor * Num2Extended(TargetRectParam.bottom));
  183.         
  184.             TheBitMap.rowBytes := (((TheBitMap.bounds.right - TheBitMap.bounds.left) + 15) div 16) * 2;
  185.             TheBitMap.baseAddr := 
  186.                     NewPtr(LONGINT(TheBitMap.rowBytes) * 
  187.                             LONGINT((TheBitMap.bounds.bottom - TheBitMap.bounds.top)));
  188.             
  189.             { Set up the return value at this point, and then fail if the allocation failed.}
  190.             IF (TheBitMap.baseAddr = NIL) THEN Exit(GenerateBitmap);
  191.             
  192.             { Remember the old GrafPort }
  193.             GetPort(OldGrafPtr);
  194.             
  195.             { Set up the new GrafPort }
  196.             aGrafPtr := @aGrafPort;
  197.             
  198.             OpenPort(aGrafPtr);
  199.             
  200.             aGrafPort.portBits := TheBitMap;
  201.             aGrafPort.portRect := TheBitMap.bounds;
  202.             RectRgn(aGrafPort.visRgn, TheBitMap.bounds);
  203.             RectRgn(aGrafPort.clipRgn, TheBitMap.bounds);
  204.             
  205.             { Clear all of the bits in the bitmap to zeros }
  206.             EraseRgn(aGrafPort.clipRgn);
  207.  
  208.             { And do the drawing -- which may fail & make us unwind & fail, too}
  209.             IF (DoTheDrawing(TheBitMap.bounds) <> TRUE)
  210.             THEN BEGIN
  211.                 DisposPtr(TheBitMap.baseAddr);
  212.                 TheBitMap.baseAddr := NIL; { The signal of failure }
  213.             END;
  214.             
  215.             { Restore the original GrafPort }
  216.             SetPort(OldGrafPtr);
  217.  
  218.             { Free the GrafPort we’ve been using}
  219.             ClosePort(aGrafPtr);
  220.         END;
  221.                 
  222.         PROCEDURE DisposeBitmap(theMap: BitMap);
  223.         BEGIN
  224.             DisposPtr(theMap.baseAddr);
  225.         END;
  226.         
  227.         FUNCTION GeneratePict: PicHandle;
  228.  
  229.         VAR
  230.             OldGrafPtr:        GrafPtr;
  231.  
  232.             aGrafPort:        GrafPort;
  233.             aGrafPtr:        GrafPtr;
  234.  
  235.             ThePict:            PicHandle;
  236.         BEGIN
  237.         
  238.             {The default return value is NIL: failure }
  239.             GeneratePict := NIL;
  240.         
  241.             { Make the bitmap and fail if it failed.}
  242.             GenerateBitmap;
  243.             IF TheBitmap.baseAddr = NIL THEN Exit(GeneratePict);
  244.             
  245.             { Remember the old GrafPort }
  246.             GetPort(OldGrafPtr);
  247.             
  248.             { Set up a new GrafPort }
  249.             aGrafPtr := @aGrafPort;
  250.             
  251.             OpenPort(aGrafPtr);
  252.         
  253.             aGrafPort.portRect := TargetRectParam;
  254.             RectRgn(aGrafPort.visRgn, TargetRectParam);
  255.             RectRgn(aGrafPort.clipRgn, TargetRectParam);
  256.  
  257.             { Open the Pict }
  258.             ThePict := OpenPicture(TargetRectParam);
  259.                     
  260.             { Copy the bitmap onto the pict -- not really onto the current port.}
  261.             CopyBits(theBitmap, aGrafPort.portBits, TheBitmap.bounds, TargetRectParam, srcCopy, NIL);
  262.             
  263.             { Dispose of the bitmap that was created. }
  264.             DisposeBitmap(TheBitmap);
  265.             
  266.             { Close and return }
  267.             ClosePicture;
  268.             GeneratePict := ThePict;
  269.  
  270.             { Restore the original GrafPort }
  271.             SetPort(OldGrafPtr);
  272.             
  273.             { Free the GrafPort we’ve been using}
  274.             ClosePort(aGrafPtr);
  275.         END;
  276.                         
  277.         PROCEDURE DisposePict(ThePict: PicHandle);
  278.         BEGIN
  279.             KillPicture(ThePict);
  280.         END;
  281.             
  282.         FUNCTION PutPictOntoClipboard(ThePict: PicHandle): OsErr;
  283.         VAR
  284.             ErrValue:        LONGINT;
  285.         BEGIN
  286.  
  287.             ErrValue := ZeroScrap;
  288.             PutPictOntoClipboard := ErrValue;
  289.             IF (ErrValue <> NoErr)
  290.             THEN Exit(PutPictOntoClipboard);
  291.             
  292.             HLock(Handle(ThePict));
  293.             ErrValue := PutScrap(GetHandleSize(Handle(ThePict)),'PICT', Ptr(ThePict^));
  294.             HUnlock(Handle(ThePict));
  295.             
  296.             PutPictOntoClipboard := ErrValue;
  297.             IF (ErrValue <> NoErr)
  298.             THEN Exit(PutPictOntoClipboard);
  299.             
  300.         END;
  301.  
  302.         PROCEDURE CleanUpBeforeEnding;
  303.         BEGIN
  304.             DisposePict(ThePict);
  305.         END;
  306.             
  307.         PROCEDURE FailWithError(aString: Str255);
  308.         BEGIN
  309.  
  310.             CleanUpBeforeEnding;
  311.             ExitWithError(aString);
  312.         END;
  313.  
  314.         PROCEDURE ParseParams;
  315.         VAR
  316.             ParamNum:            integer;
  317.         BEGIN
  318.             WITH paramPtr^ DO 
  319.             BEGIN
  320.                 IF (paramCount < MinParams) THEN ExitWithError('Too few parameters');
  321.                 IF (paramCount > MaxParams) THEN ExitWithError('Too many parameters');
  322.             
  323.                 ParamNum := 1; {* Required *}
  324.                 
  325.                 ZeroToPas(ParamPtr, Params[ParamNum]^, ParamStrings[ParamNum]);
  326.                 StrToRect(paramPtr, ParamStrings[ParamNum], TargetRectParam);
  327.                 LimitRectValue(TargetRectParam);
  328.                 
  329.                 ParamNum := 2; {* Required *}
  330.                 
  331.                 ZeroToPas(paramPtr, Params[ParamNum]^, ParamStrings[ParamNum]);
  332.                 TextLabelParam := ParamStrings[ParamNum];
  333.                 
  334.                 ParamNum := 3; {* Optional *}
  335.                 
  336.                 IF (paramCount >= ParamNum) THEN
  337.                     BEGIN
  338.                         ZeroToPas(paramPtr, params[ParamNum]^, ParamStrings[ParamNum]);  
  339.                         DPIParam := StrToNum(paramPtr, ParamStrings[ParamNum]);
  340.                         LimitDPIValue(DPIParam);
  341.                     END
  342.                 ELSE
  343.                     BEGIN
  344.                         DPIParam := 72;
  345.                     END;    
  346.                 
  347.                 
  348.             END;
  349.         END;
  350.             
  351.             
  352.     BEGIN {DrawBitmapInRect}
  353.  
  354.         WITH paramPtr^ DO
  355.         BEGIN
  356.         
  357.             ParseParams;
  358.  
  359.             ScaleFactor := Num2Extended(DPIParam) / Num2Extended(72); { 1.0 <= ScaleFactor < 5.0 }
  360.         
  361.             ThePict := GeneratePict;
  362.             IF (ThePict = NIL) THEN 
  363.             ExitWithError('Failed while generating picture');
  364.             
  365.             IF (PutPictOntoClipboard(ThePict) <> NoErr)
  366.             THEN FailWithError('Couldn’t place PICT on clipboard');
  367.             
  368.             CleanUpBeforeEnding; { i.e. dispose of the PICT before quitting }
  369.  
  370.             ExitWithString('');
  371.             
  372.         END
  373.  
  374.     END { DrawBitmapInRect } ;
  375.  
  376. END. { DummyUnit }
  377.  
  378.  
  379.